﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static CCS_Snake.Contracts;

namespace CCS_Snake
{
    class GameEvent
    {
        /// <summary>
        /// 时间倒计时线程
        /// </summary>
        /// <param name="parameter"></param>
        public static void ThreadTimeCountDown(object parameter)
        {
            object[] __parameter = (object[])parameter;
            Form form = (Form)__parameter[0];
            Label label = (Label)__parameter[1];

            if (label.InvokeRequired)
            {
                do
                {
                    if (Parameter.GameState.ToUpper() == "RUNNING")
                    {
                        int currentTime = Utils.TimeToInt(label.Text);
                        currentTime += 1;
                        form.BeginInvoke(new Action(() => { label.Text = Utils.IntToTime(currentTime); }));
                        Thread.Sleep(1000);
                    } else
                    {
                        Thread.Sleep(1);
                    }
                } while (true);
            }
        }

        /// <summary>
        /// 清空地图
        /// </summary>
        /// <param name="mapPaint"></param>
        /// <param name="map"></param>
        public static void MapClear(MapPaintStruct mapPaint, Graphics map)
        {
            int rowCellCount = mapPaint.RowCellCount;
            int colCellCount = mapPaint.ColCellCount;
            int cellSizeStep = mapPaint.CellSizeStep;
            Color lineColor = mapPaint.LineColor;
            Color backgroundColor = mapPaint.BackgroundColor;

            map.FillRectangle(new SolidBrush(backgroundColor), 0, 0, colCellCount * cellSizeStep, rowCellCount * cellSizeStep);

            for (int rowIndex = 0; rowIndex <= rowCellCount; rowIndex++)
            {
                map.DrawLine(
                    new Pen(lineColor),
                    new Point(0, rowIndex * cellSizeStep),
                    new Point(rowCellCount * cellSizeStep, rowIndex * cellSizeStep)
                );
            }

            for (int colIndex = 0; colIndex <= colCellCount; colIndex++)
            {
                map.DrawLine(
                    new Pen(lineColor),
                    new Point(colIndex * cellSizeStep, 0),
                    new Point(colIndex * cellSizeStep, colCellCount * cellSizeStep)
                );
            }
        }

        /// <summary>
        /// 游戏运行线程
        /// </summary>
        /// <param name="parameter"></param>
        public static void ThreadGameRunning(object parameter)
        {
            object[] __parameter = (object[])parameter;
            Form form = (Form)__parameter[0];
            MapPaintStruct mapPaint = (MapPaintStruct)__parameter[1];
            Graphics map = (Graphics)__parameter[2];
            SnakeColorStruct snakeColor = (SnakeColorStruct)__parameter[3];
            Button button = (Button)__parameter[4];
            Label lblLength = (Label)__parameter[5];
            Label lblScore = (Label)__parameter[6];

            do
            {
                if (Parameter.GameState.ToUpper() == "RUNNING")
                {
                    // 从键盘按键列表中读取方向按键
                    SetSnakeMoveDirection();

                    // 根据运行方向绘制点
                    Point snakeHead = Parameter.SnakeBody[0];
                    switch (Parameter.SnakeDirection)
                    {
                        case Parameter.MoveDirection.ToUp:
                            snakeHead.Y -= 1;
                            break;
                        case Parameter.MoveDirection.ToDown:
                            snakeHead.Y += 1;
                            break;
                        case Parameter.MoveDirection.ToLeft:
                            snakeHead.X -= 1;
                            break;
                        case Parameter.MoveDirection.ToRight:
                            snakeHead.X += 1;
                            break;
                    }

                    // 允许贪吃蛇穿墙
                    if (snakeHead.Y < 0) snakeHead.Y = mapPaint.RowCellCount - 1;
                    if (snakeHead.Y >= mapPaint.RowCellCount) snakeHead.Y = 0;
                    if (snakeHead.X < 0) snakeHead.X = mapPaint.ColCellCount - 1;
                    if (snakeHead.X >= mapPaint.ColCellCount) snakeHead.X = 0;

                    // 判断蛇是否碰到蛇身, 意味着游戏结束了
                    if (Parameter.SnakeBody.Contains(snakeHead) && Parameter.SnakeBody.Last() != snakeHead)
                    {
                        form.BeginInvoke(new Action(() => { button.PerformClick(); }));
                    }
                    // 判断蛇是否吃到食物
                    if (Parameter.Food == snakeHead)
                    {
                        Parameter.SnakeBody.Add(Parameter.Food);
                        Parameter.Food = new Point(-1, -1);

                        form.BeginInvoke(new Action(() => {
                            int score = Convert.ToInt32(lblLength.Text) + 1;
                            lblLength.Text = score.ToString();

                            if (Convert.ToInt32(lblScore.Text) < score) lblScore.Text = score.ToString();
                        }));
                    }

                    // 更新贪吃蛇状态
                    Parameter.SnakeBody.Insert(0, snakeHead);
                    Parameter.SnakeBody.RemoveAt(Parameter.SnakeBody.Count - 1);

                    // 当食物不存在时, 创建食物
                    Point food = Utils.RandomFoodPoint(Parameter.Food, mapPaint, Parameter.SnakeBody);
                    if (food != new Point(-1, -1)) Parameter.Food = food;

                    // 绘制食物
                    DrawFood(mapPaint, map, snakeColor);

                    // 绘制贪吃蛇
                    DrawSnake(mapPaint, map, snakeColor);

                    // 移动速度
                    Thread.Sleep(100);
                } else
                {
                    Thread.Sleep(1);
                }
            } while (true);
        }

        /// <summary>
        /// 绘制贪吃蛇
        /// </summary>
        /// <param name="mapPaint"></param>
        /// <param name="map"></param>
        /// <param name="snakeColor"></param>
        public static void DrawSnake(MapPaintStruct mapPaint, Graphics map, SnakeColorStruct snakeColor)
        {
            int index = 0;
            Color head = snakeColor.Body;
            Color tail = snakeColor.Tail;
            int redSpace = tail.R - head.R;
            int greenSpace = tail.G - head.G;
            int blueSpace = tail.B - head.B;

            int colorStep = Parameter.SnakeBody.Count;
            foreach (Point item in Parameter.SnakeBody)
            {
                Color color = Color.FromArgb(
                    head.R + (int)((double)index / colorStep * redSpace),
                    head.G + (int)((double)index / colorStep * greenSpace),
                    head.B + (int)((double)index / colorStep * blueSpace)
                );

                if (index == 0) color = snakeColor.Head;
                if (index == Parameter.SnakeBody.Count - 1) color = mapPaint.BackgroundColor;

                int size = mapPaint.CellSizeStep;
                map.FillRectangle(new SolidBrush(color), item.X * size + 1, item.Y * size + 1, size - 1, size - 1);

                index += 1;
            }
        }

        /// <summary>
        /// 设置贪吃蛇的移动方向, 从键盘消息队列中取出最新的键盘事件, 避免按键粘连
        /// </summary>
        private static void SetSnakeMoveDirection()
        {
            int currentMoveDirection = Parameter.SnakeDirection;
            int newMoveDirection = currentMoveDirection;

            if (Parameter.SnakeDirectionList.Count > 0)
            {
                switch (Parameter.SnakeDirectionList.Last())
                {
                    case Parameter.MoveDirection.ToUp:
                        if (currentMoveDirection != Parameter.MoveDirection.ToDown) newMoveDirection = Parameter.MoveDirection.ToUp;
                        break;
                    case Parameter.MoveDirection.ToDown:
                        if (currentMoveDirection != Parameter.MoveDirection.ToUp) newMoveDirection = Parameter.MoveDirection.ToDown;
                        break;
                    case Parameter.MoveDirection.ToLeft:
                        if (currentMoveDirection != Parameter.MoveDirection.ToRight) newMoveDirection = Parameter.MoveDirection.ToLeft;
                        break;
                    case Parameter.MoveDirection.ToRight:
                        if (currentMoveDirection != Parameter.MoveDirection.ToLeft) newMoveDirection = Parameter.MoveDirection.ToRight;
                        break;
                }
            }

            Parameter.SnakeDirection = newMoveDirection;
            Parameter.SnakeDirectionList = new List<int>();
        }

        /// <summary>
        /// 绘制食物
        /// </summary>
        /// <param name="mapPaint"></param>
        /// <param name="map"></param>
        /// <param name="snakeColor"></param>
        private static void DrawFood(MapPaintStruct mapPaint, Graphics map, SnakeColorStruct snakeColor)
        {
            int size = mapPaint.CellSizeStep;
            Point food = Parameter.Food;
            map.FillRectangle(new SolidBrush(snakeColor.Food), food.X * size + 1, food.Y * size + 1, size - 1, size - 1);
        }
    }
}
